package model;

import org.mybeans.dao.DAOException;
import org.mybeans.factory.BeanFactory;
import org.mybeans.factory.BeanFactoryException;
import org.mybeans.factory.BeanTable;
import org.mybeans.factory.DuplicateKeyException;
import org.mybeans.factory.MatchArg;
import org.mybeans.factory.RollbackException;
import org.mybeans.factory.Transaction;

import databeans.Answer;
import interfas.AnswerInterface;

public class AnswerDAO implements AnswerInterface {

	private BeanFactory<Answer> factory;
	
	public AnswerDAO() throws DAOException {
		try {
			BeanTable<Answer> table = BeanTable.getInstance(Answer.class, "answer");
			if (!table.exists())
				table.create("qid", "username", "entityname", "answer");
			
			table.setIdleConnectionCleanup(true);
			factory = table.getFactory();
		} catch (BeanFactoryException e) {
			throw new DAOException(e);
		}
	}
	
	public void create(Answer answer, QuestionDAO questionDAO, UserDAO userDAO, EntityDAO entityDAO) throws DAOException {
		try {
			// Check for foreign key constraint
			if (questionDAO.lookup(answer.getQid()) == null) {
				throw new DAOException("qid must exist in question table");
			}
			if (userDAO.lookup(answer.getUsername()) == null) {
				throw new DAOException("username must exist in user table");
			}
			if (!(answer.getEntityname().equals("")) && entityDAO.getEntityByName(answer.getEntityname()) == null) {
				throw new DAOException("entityname must exist in entity table");
			}
			
			Transaction.begin();
			Answer dbAnswer = factory.create(answer.getQid(), answer.getUsername(), answer.getEntityname(), answer.getAnswer());
			factory.copyInto(answer, dbAnswer);
			Transaction.commit();
		} catch (DuplicateKeyException e) {
			throw new DAOException("An answer with qid " + answer.getQid() + ", username " + answer.getUsername() +
					", entityname " + answer.getEntityname() + " and answer " + answer.getAnswer() + " doesn't exist");
		} catch (RollbackException e) {
			throw new DAOException(e);
		} finally {
			if (Transaction.isActive())
				Transaction.rollback();
		}
	}

	public Answer lookup(int qid, String username, String entityname, String answer) throws DAOException {
		try {
			return factory.lookup(qid, username, entityname, answer);
		} catch (RollbackException e) {
			throw new DAOException(e);
		}
	}
	
	public Answer[] getAnswerByQidUsername(int qid, String username) throws DAOException {
		try {
			return factory.match(MatchArg.equals("qid", qid), MatchArg.equals("username", username));
		} catch (RollbackException e) {
			throw new DAOException(e);
		}
	}
	
	//Non-network version of getAnswerByQidUsername, should return only one answer
	public Answer getAnswerByQidUsernameNN(int qid, String username) throws DAOException {
		try {
			Answer[] ans = factory.match(MatchArg.equals("qid", qid), MatchArg.equals("username", username), MatchArg.equals("entityname", ""));
			if (ans.length == 0)
				return null;
			return ans[0];
		} catch (RollbackException e) {
			throw new DAOException(e);
		}
	}
	
	public boolean existAnswerByQidUsername(int qid, String username) throws DAOException {
		try {
			Answer[] ans = factory.match(MatchArg.equals("qid", qid), MatchArg.equals("username", username));
			if (ans == null || ans.length == 0)
				return false;
			return true;
		} catch (RollbackException e) {
			throw new DAOException(e);
		}
	}
	
	public void delete(int qid, String username, String entityname, String answer) throws DAOException {
		try {
			Transaction.begin();
			Answer dbAnswer = lookup(qid, username, entityname, answer);
			if (dbAnswer == null)
				throw new DAOException("An answer with qid " + qid + ", username " + username +
						", entityname " + entityname + " and answer " + answer + " already exists");
			factory.delete(qid, username, entityname, answer);
			Transaction.commit();
		} catch (RollbackException e) {
			throw new DAOException(e);
		} finally {
			if (Transaction.isActive())
				Transaction.rollback();
		}
	}

	public int size() throws DAOException {
		try {
			return factory.getBeanCount();
		} catch (RollbackException e) {
			throw new DAOException(e);
		}
	}
}
